package me.yuzhou.weixin.util;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.json.Json;

import me.yuzhou.weixin.menu.Button;
import me.yuzhou.weixin.menu.ClickButton;
import me.yuzhou.weixin.menu.Menu;
import me.yuzhou.weixin.menu.ViewButton;
import me.yuzhou.weixin.po.AccessToken;
import net.sf.json.JSONObject;

@SuppressWarnings("deprecation")
public class WeixinUtil {

	private static Logger logger = LoggerFactory.getLogger(WeixinUtil.class);
	
	private static final String APPID = "wx432cd0049cefd528";
	private static final String APPSECRET = "d0edcc59b11326786ec7694556dad93c";
	
	private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
	private static final String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s";
	private static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s";
	private static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s";
	private static final String QUERY_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s";
	
	@SuppressWarnings("resource")
	public static JSONObject doGetStr(String url) {
		
		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(url);
		
		JSONObject jsonObject = null;
		
		try {
			HttpResponse response = httpClient.execute(httpGet);
			HttpEntity entity = response.getEntity();
			
			if(entity != null) {
				
				String result = EntityUtils.toString(entity, "UTF-8");
				jsonObject = JSONObject.fromObject(result);
				
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return jsonObject;
	}
	
	@SuppressWarnings("resource")
	public static JSONObject doPostStr(String url, String outStr) {
		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost(url);
		
		JSONObject jsonObject = null;
		httpPost.setEntity(new StringEntity(outStr, "UTF-8"));
		
		try {
			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			
			if(null != entity) {
				String result = EntityUtils.toString(entity, "UTF-8");
				jsonObject = JSONObject.fromObject(result);
			}
			
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return jsonObject;
	}
	
	/** 获取 access token
	 * @return
	 */
	public static AccessToken getAccessToken() {
		AccessToken accessToken = null; 
		
		String url = String.format(ACCESS_TOKEN_URL, APPID, APPSECRET);
	
		logger.info("Get access token from URL: {}", url);
		
		JSONObject jsonObject = doGetStr(url);
		
		if(null != jsonObject) {
			
			if(null != jsonObject.get("errcode")) {
				String errMsg = jsonObject.getString("errmsg");
				logger.error("Fail to access token, caused by: {} ", errMsg);
				
			} else {
			
				accessToken = new AccessToken();
				accessToken.setAccessToken(jsonObject.getString("access_token"));
				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
			}
		} else {
			
			logger.error("Fail to access token ");
		}
		
		
		return accessToken;
	}
	
	/** 文件上传：媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb）
	 * @return
	 * @throws IOException 
	 */
	public static String upload(String filePath, String accessToken, String type) throws IOException { 
		
		File file = new File(filePath);
		
		if(!file.exists() || !file.isFile()) {
			logger.error("The file {} does not exist", filePath);
			return null;
		}
		
		String url = String.format(UPLOAD_URL, accessToken, type);
		
		URL urlObj = new URL(url);
		
		//建立连接
		HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
		
		conn.setRequestMethod("POST");
		conn.setDoInput(true);
		conn.setDoOutput(true);
		conn.setUseCaches(false);
		
		// 设置请求头信息
		conn.setRequestProperty("Connection", "Keep-Alive");
		conn.setRequestProperty("Charset", "UTF-8");
		
		// 设置边界
		String BOUNDARY = "----------" + System.currentTimeMillis();
		conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
		
		StringBuilder sb = new StringBuilder();
		sb.append("--");
		sb.append(BOUNDARY);
		sb.append("\r\n");
		sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
		sb.append("Content-Type:application/octet-stream\r\n\r\n");
		
		byte[] head = sb.toString().getBytes("UTF-8");
		
		//获得输出流
		OutputStream out = new DataOutputStream(conn.getOutputStream());
		
		//输出表头
		out.write(head);
		
		//输出文件正文部分，将文件以流的方式输出
		DataInputStream in = new DataInputStream(new FileInputStream(file));
		int bytes = 0;
		
		byte[] bufferOut = new byte[1024];
		while ((bytes = in.read(bufferOut)) != -1) { //读取到文件内容
			out.write(bufferOut, 0, bytes); //将读取到的内容推送到URL
		}
		in.close();
		
		//结尾部分
		byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");//定义最后数据分隔线

		out.write(foot);

		out.flush();
		out.close();

		StringBuffer buffer = new StringBuffer();
		BufferedReader reader = null;
		String result = null;
		try {
			//定义BufferedReader输入流来读取URL的响应
			reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			if (result == null) {
				result = buffer.toString();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				reader.close();
			}
		}

		JSONObject jsonObj = JSONObject.fromObject(result);
		logger.info("Upload result: {}", jsonObj);
		
		String typeName = "media_id";
		if(!"image".equals(type)){
			typeName = type + "_media_id";
		}
		String mediaId = jsonObj.getString(typeName);
		return mediaId;
	}
	
	/** 组装菜单
	 * @return
	 */
	public static Menu initMenu() {
		Menu menu = new Menu();
		
		ClickButton button11 = new ClickButton();
		button11.setName("click菜单");
		button11.setType("click");
		button11.setKey("11");
		
		ViewButton button21 = new ViewButton();
		button21.setName("view菜单");
		button21.setType("view");
		button21.setUrl("http://www.qq.com");
		
		ClickButton button31 = new ClickButton();
		button31.setName("扫码事件");
		button31.setType("scancode_push");
		button31.setKey("31");
		
		ClickButton button32 = new ClickButton();
		button32.setName("地理位置");
		button32.setType("location_select");
		button32.setKey("32");
		
		Button button = new Button();
		button.setName("菜单");
		button.setSub_button(new Button[] { button31, button32 });
		
		menu.setButton(new Button[] {button11, button21, button});
		return menu;
	}
	
	public static int createMenu(String token, String menu) {
		int result = 0;
		
		String url = String.format(CREATE_MENU_URL, token);
		
		JSONObject jsonObject = doPostStr(url, menu);
		
		if(null != jsonObject) {
			result = jsonObject.getInt("errcode");
			if(result != 0 ) {
				logger.error("Fail to create menu: {}", jsonObject);
			}
		}
		
		return result;
	}
	
	public static JSONObject queryMenu(String token) {
		String url = String.format(QUERY_MENU_URL, token);
		
		JSONObject jsonObject = doGetStr(url);
		
		return jsonObject;
	}
	
	public static int deleteMenu(String token) {
		String url = String.format(DELETE_MENU_URL, token);
		
		JSONObject jsonObject = doGetStr(url);
		
		int result = 0;
		
		if(jsonObject != null) {
			result = jsonObject.getInt("errcode");
			
			if(result != 0 ) {
				logger.error("Fail to delete menu: {}", jsonObject);
			}
		}
		
		
		
		return result;
	}
	
}
